package sundun.sharding.common;

import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingValue;
import sundun.sharding.common.complex.ComplexShardingParam;
import sundun.sharding.common.complex.ComplexShardingParamValue;
import sundun.sharding.common.complex.ComplexShardingType;
import sundun.sharding.properties.ShardingJdbcProperties;

import java.util.*;

/**
 * @author: zxl
 * @date: 2024/07/31 16:12
 */
@Slf4j
public abstract  class AbstractComplexSharding<T extends Comparable<? super T>>{



    /**
     * 初始化分库分表参数时处理复合分片键的逻辑。
     * 此方法会根据提供的复合分片信息，将分片参数初始化为一个参数列表，每个参数对应一个分片键的值或值范围。
     *
     * @param shardingValue 包含复合分片键信息的对象，其中包含了按具体列名分组的分片值集合以及按列名分组的范围分片值集合。
     * @return 返回一个包含所有初始化好的分片参数的列表。
     */
    protected ComplexShardingType complexKeyInitSharingParams(ComplexKeysShardingValue<Comparable<?>> shardingValue) {

        ComplexShardingType complexShardingType = new ComplexShardingType();
        List<ComplexShardingParam> shardingParam = new ArrayList<>();
        // 处理显式提供的分片值
        Map<String, Collection<Comparable<?>>> valuesMap = shardingValue.getColumnNameAndShardingValuesMap();
        String columName;
        if (MapUtils.isNotEmpty(valuesMap)) {
            for (Map.Entry<String, Collection<Comparable<?>>> entry : valuesMap.entrySet()) {
                Collection<Comparable<?>> values = entry.getValue();
                columName = entry.getKey();
                if (CollectionUtils.isNotEmpty(values)) {
                    ComplexShardingParam fromCollection = this.initShardingParamsFromCollection(values, columName);
                    shardingParam.add(fromCollection);
                }
            }
        }
        // 处理范围分片值
        Map<String, Range<Comparable<?>>> rangeValuesMap = shardingValue.getColumnNameAndRangeValuesMap();
        if (MapUtils.isNotEmpty(rangeValuesMap)) {
            for (Map.Entry<String, Range<Comparable<?>>> rangeEntry : rangeValuesMap.entrySet()) {
                Range<Comparable<?>> range = rangeEntry.getValue();
                columName = rangeEntry.getKey();
                if (Objects.nonNull(range)) {
                    ComplexShardingParam param = this.initShardingParamsFromRange(range, columName);
                    shardingParam.add(param);
                }
            }
            complexShardingType.setIsAddData(false);
        }
        complexShardingType.setShardingParam(shardingParam);
        return complexShardingType;
    }

    /**
     * =，in时分表信息参数组装
     *
     * @param collection 字段值
     * @param shardingColumn 分片字段
     * @return
     */
    protected ComplexShardingParam initShardingParamsFromCollection(Collection<Comparable<?>> collection, String shardingColumn) {
        ComplexShardingParam param = new ComplexShardingParam();
        // 有多个参数时，就不是单值
        if (collection.size() >= 2) {
            param.setSingleValue(false);
        }
        List<Comparable<?>> list = new ArrayList<>();
        list.addAll(collection);
        param.setColumnName(shardingColumn);
        ComplexShardingParamValue paramValue = new ComplexShardingParamValue();
        if (list.size() == 1) {
            paramValue.setSingleValue(list.get(0));
        } else {
            paramValue.setListValue(list);
        }
        param.setComplexShardingParamValue(paramValue);
        return param;
    }


    /**
     * 包含>=,<=,>,<,> between and 时分表信息参数组装
     *
     * @param range
     * @param shardingColumn
     * @return
     */
    protected ComplexShardingParam initShardingParamsFromRange(Range<Comparable<?>> range, String shardingColumn) {
        ComplexShardingParam param = new ComplexShardingParam();
        // 范围查询，就不是单值
        param.setSingleValue(false);
        param.setColumnName(shardingColumn);
        ComplexShardingParamValue paramValue = new ComplexShardingParamValue();
        paramValue.setUpperBound(range.hasUpperBound());
        paramValue.setLowerBound(range.hasLowerBound());
        //存在上区间
        if (range.hasUpperBound()) {
            paramValue.setUpperEndPoint(range.upperEndpoint());
            paramValue.setUpperBoundType(range.upperBoundType());
        }
        //存在下区间
        if (range.hasLowerBound()) {
            paramValue.setLowerEndPoint(range.lowerEndpoint());
            paramValue.setLowerBoundType(range.lowerBoundType());
        }
        param.setComplexShardingParamValue(paramValue);
        return param;
    }


    /**
     * 针对取模分片键自定义分片规则
     * @param singleValue 分片字段值
     * @param tableName 前缀拼接 表名_日期
     * @param shardingResult  返回拼接后的查询节点
     * @param shardingJdbcProperties 配置类
     */
    protected abstract void deliveryAlgorithm(String singleValue,String  tableName,Collection<String> shardingResult,
                                   ShardingJdbcProperties shardingJdbcProperties);





}
